﻿using System;
using System.Collections.Generic;
using SimpleInjector;
using System.Web.Http;
using System.Collections.Concurrent;
using Sustainalytics.Alerts.AlertsEngine;
using Sustainalytics.Claims;
using Sustainalytics.ClientDW.Entities.Alerts;
using Sustainalytics.DataLayer.ConnectionStrings;
using Sustainalytics.Blob;
using Sustainalytics.Entities;
using System.Configuration;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.MongoDB.Extensions;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.ClientDW.Entities.Universes;
using Sustainalytics.ClientDW.DataAccessLayer;
using Sustainalytics.Portfolios.BL;

namespace Sustainalytics.Alerts.Service
{
    public static class CompositionRoot

    { 
        public static Container RegisterDependencies(HttpConfiguration config)
        {
            var container = new Container();

            container.Options.DefaultScopedLifestyle = new SimpleInjector.Lifestyles.AsyncScopedLifestyle();
            container.RegisterWebApiControllers(config);

            var storageConnectionString = ConfigurationManager.AppSettings["StorageAccountConnectionString"];
            var blobAlertsContainer = ConfigurationManager.AppSettings["Blob_AlertsContainer"];
            var clientPlatformConnectionString = ConfigurationManager.ConnectionStrings["ClientPlatform"].ToString();
    
            DeploymentLocation deploymentLocation = (DeploymentLocation)Enum.Parse(typeof(DeploymentLocation), ConfigurationManager.AppSettings["DeploymentLocation"]);

            var alertsDictionary = new Dictionary<Guid, CompanyAlert>();

            container.RegisterMisc(storageConnectionString, clientPlatformConnectionString, blobAlertsContainer, deploymentLocation);

            container.RegisterRepositories();

            container.RegisterCollections(clientPlatformConnectionString);

            container.RegisterBussinessLogic(clientPlatformConnectionString, alertsDictionary);

            container.Verify();
            return container;
        }

        private static void RegisterCollections(this Container container, string clientPlatformConnectionString)
        {
            container.Register(typeof(IConnectionStringsRepository), () => new ConnectionStringsRepository(clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<Alert>), () => new RepositoryCollection<Alert>(MongoFactory.GetConnectionStrings().ClientDW));
            container.Register(typeof(IRepositoryCollection<CorporateData>), () => new RepositoryCollection<CorporateData>(MongoFactory.GetConnectionStrings().ClientDW));
            container.Register(typeof(IRepositoryCollection<UniverseCompany>), () => new RepositoryCollection<UniverseCompany>(
                MongoFactory.GetConnectionStrings().ClientUniverses));
            container.Register(typeof(IRepositoryCollection<CorporateDataBasic>), () => new RepositoryCollection<CorporateDataBasic>(MongoFactory.GetConnectionStrings().ClientDW, "CorporateData"));
            container.Register(typeof(IRepositoryCollection<Account>), () => new RepositoryCollection<Account>(clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<User>), () => new RepositoryCollection<User>(clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<Portfolio>), () => new RepositoryCollection<Portfolio>(clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<PortfolioDetails>), () => new RepositoryCollection<PortfolioDetails>(clientPlatformConnectionString));
        }

        private static void RegisterRepositories(this Container container)
        {
     
            container.Register(() => UniversesRepository.GetUniversesRepository(MongoFactory.GetConnectionStrings().ClientUniverses));
        }

     
        private static void RegisterBussinessLogic(this Container container, string clientPlatformConnectionString, Dictionary<Guid, CompanyAlert> alertsDictionary)
        {
            
            container.Register(typeof(IPorfolioNamesCache), () => new PorfolioNamesCache(new ConcurrentDictionary<Guid, string>()));
            container.Register(typeof(IFeatureUniversesCache), () => new FeatureUniversesCache(new ConcurrentDictionary<Guid, List<int>>()));
            container.Register(typeof(IPortfolioCompanyCache), ()=> new PortfolioCompanyCache(new PorfolioNamesCache(new ConcurrentDictionary<Guid, string>())));

            container.Register(() => new PortfolioTypeCollection<Portfolio>(
                new RepositoryCollection<Portfolio>(clientPlatformConnectionString),
                new RepositoryCollection<Portfolio>(MongoFactory.GetConnectionStrings().ClientDW)));
            container.Register(() => new PortfolioTypeCollection<PortfolioDetails>(
                new RepositoryCollection<PortfolioDetails>(clientPlatformConnectionString),
                new RepositoryCollection<PortfolioDetails>(MongoFactory.GetConnectionStrings().ClientDW)));

            container.Register(typeof(IPortfolioReadHandler), () => new PortfolioReadHandler(
                  container.GetInstance<PortfolioTypeCollection<Portfolio>>(),
                  container.GetInstance<PortfolioTypeCollection<PortfolioDetails>>(),
                  container.GetInstance<IRepositoryCollection<CorporateDataBasic>>()));
    
            container.Register(typeof(IAlertsSubscription), ()=>new AlertsSubscription(
                container.GetInstance<IOperationClaimsRetriever>(),
                container.GetInstance<IRepositoryCollection<User>>(),
                container.GetInstance<IRepositoryCollection<Account>>(),
                container.GetInstance<IRepositoryCollection<UniverseCompany>>(),
                container.GetInstance<IUniversesRepository>(),
                container.GetInstance<IPortfolioReadHandler>()
                ));

            container.Register(typeof(IAlertsManager), () => new AlertsManager(
                alertsDictionary,
                container.GetInstance<IRepositoryCollection<Alert>>(),
                container.GetInstance<IRepositoryCollection<CorporateData>>()));

        }

        private static void RegisterMisc(
            this Container container, string storageConnectionString, string clientPlatformConnectionString,string blobContainer , DeploymentLocation deploymentLocation)
        {
            container.Register(typeof(IOperationClaimsRetriever), () => new OperationClaimsRetriever());
            container.Register(()=> ConnectionStringsManager.GetInstance(new ConnectionStringsRepository(clientPlatformConnectionString)));
            container.Register(typeof(IBlobManager), ()=> new  BlobManager(storageConnectionString, blobContainer, deploymentLocation));
            container.Register(typeof(IBlobHelper), () => new BlobHelper(container.GetInstance<IBlobManager>()));
        }
    }
}

